from typing import Optional, Tuple
from const import (
    BLUE, INITIAL_GRID_SIZE, RED,
    Skill,
    NEUTRAL_PIECE_ICON,
)



class Player:
    """
    玩家类，存储玩家信息
    """
    def __init__(self, name: str, symbol: str, color: Tuple[int, int, int]):
        self.name = name
        self.symbol = symbol
        self.color = color
        self.skills = {
            Skill.CLEAR_ROW: 2, 
            Skill.CLEAR_COLUMN: 2, 
            Skill.EXPAND_GRID: 1, 
            Skill.SWAP_PIECES: 1,
            Skill.MOVE_PIECE: 1,
        }  # 技能及其使用次数
        # self._available_skills = [Skill.CLEAR_COLUMN, Skill.CLEAR_ROW]  # 可用技能列表
    
    def use_skill(self, skill_name: str) -> bool:
        """
        使用技能
        :param skill_name: 要使用的技能名称
        :return: 如果技能成功使用返回 True，否则返回 False
        """
        # 检查技能名称是否在玩家拥有的技能列表中，并且该技能的可用次数大于 0
        if skill_name in self.skills and self.skills[skill_name] > 0:
            # 若条件满足，将该技能的可用次数减 1
            self.skills[skill_name] -= 1
            return True
        return False
    
    @property
    def skill_uses(self) -> dict[Skill, int]:
        return self.skills


    @property
    def available_skills(self) -> list[Skill]:
        """
        获取可用技能列表
        """
        return [skill for skill in self.skills if self.skills[skill] > 0]

class PlayerManager:
    """
    管理玩家信息，包括棋子样式、技能使用、存活状态
    """
    def __init__(self):
        self.players = [
            Player("Player A", "A", RED),
            Player("Player B", "B", BLUE)
        ]
        self.current_player_index = 0
    
    @property
    def current_player(self) -> Player:
        """
        获取当前玩家
        """
        return self.players[self.current_player_index]
    
    def switch_player(self) -> None:
        """
        切换玩家
        """
        self.current_player_index = (self.current_player_index + 1) % len(self.players)

class GridManager:
    """
    管理棋盘数据，处理网格扩展、不可玩区域、棋子移动/交换逻辑
    """
    def __init__(self, initial_size: int = INITIAL_GRID_SIZE):
        self.grid_size = initial_size
        self.grid = [[None for _ in range(initial_size)] for _ in range(initial_size)]
        self.trapped_cells = []  # 存储暂时无法使用的格子坐标
        self.neutral_cells = []  # 新增：存储中立棋子的格子坐标

    def place_piece(self, position: Tuple[int, int], player: Player) -> bool:
        """
        在指定位置放置棋子
        """
        x, y = position
        # 检查位置是否有效且为空，且不是trapped或neutral
        if (0 <= x < self.grid_size and 0 <= y < self.grid_size and 
            self.grid[y][x] is None and 
            (x, y) not in self.trapped_cells and 
            (x, y) not in self.neutral_cells):
            self.grid[y][x] = player.symbol
            return True
        return False

    def move_piece(self, from_pos: Tuple[int, int], to_pos: Tuple[int, int]) -> bool:
        fx, fy = from_pos
        tx, ty = to_pos
        # 验证目标位置是否有效，且不是trapped或neutral
        if (0 <= tx < self.grid_size and 0 <= ty < self.grid_size and
            self.grid[ty][tx] is None and 
            (tx, ty) not in self.trapped_cells and
            (tx, ty) not in self.neutral_cells):
            self.grid[ty][tx] = self.grid[fy][fx]
            self.grid[fy][fx] = None
            return True
        return False

    def get_empty_cells(self) -> list[Tuple[int, int]]:
        """
        获取所有可用的空格子（未被占用、未被困住、不是中立棋子）
        """
        empty_cells = []
        for y in range(self.grid_size):
            for x in range(self.grid_size):
                if (self.grid[y][x] is None and 
                    (x, y) not in self.trapped_cells and 
                    (x, y) not in self.neutral_cells):
                    empty_cells.append((x, y))
        return empty_cells

    def place_neutral_piece(self, position: Tuple[int, int]) -> bool:
        """
        在指定位置放置一个中立棋子（如 emoji），并记录到 neutral_cells
        """
        x, y = position
        if (0 <= x < self.grid_size and 0 <= y < self.grid_size and
            self.grid[y][x] is None and 
            (x, y) not in self.trapped_cells and
            (x, y) not in self.neutral_cells):
            self.grid[y][x] = NEUTRAL_PIECE_ICON  # 你可以替换为任意 emoji
            self.neutral_cells.append((x, y))
            return True
        return False

    def expand_grid(self) -> None:
        """
        扩展网格并将现有棋子移动到中心
        """
        new_size = self.grid_size + 2
        new_grid = [[None for _ in range(new_size)] for _ in range(new_size)]
        
        # 计算偏移量，将原有棋子移动到中心
        offset = 1
        for y in range(self.grid_size):
            for x in range(self.grid_size):
                if self.grid[y][x] is not None:
                    new_grid[y + offset][x + offset] = self.grid[y][x]
        
        self.grid = new_grid
        self.grid_size = new_size
        
        # 更新被困住的格子坐标
        new_trapped_cells = []
        for x, y in self.trapped_cells:
            new_trapped_cells.append((x + offset, y + offset))
        self.trapped_cells = new_trapped_cells

        # 更新中立棋子的坐标
        new_neutral_cells = []
        for x, y in self.neutral_cells:
            new_neutral_cells.append((x + offset, y + offset))
        self.neutral_cells = new_neutral_cells
    
    def is_full(self) -> bool:
        """
        检查网格是否已满（包括被困住的格子和已放置棋子的格子）
        """
        total_cells = self.grid_size * self.grid_size
        trapped_count = len(self.trapped_cells)
        occupied_count = 0
        for row in self.grid:
            for cell in row:
                if cell is not None:
                    occupied_count += 1
        # 如果被困住的格子数 + 已放置棋子的格子数 等于总格子数，则视为已满
        return (trapped_count + occupied_count) >= total_cells
    
    def clear_row(self, row_index: int) -> None:
        """
        清除指定行的所有棋子
        """
        if 0 <= row_index < self.grid_size:
            self.grid[row_index] = [None for _ in range(self.grid_size)]
            # 移除该行的所有中立棋子
            self.neutral_cells = [(x, y) for (x, y) in self.neutral_cells if y != row_index]
    
    def clear_column(self, col_index: int) -> None:
        """
        清除指定列的所有棋子
        """
        if 0 <= col_index < self.grid_size:
            for row in range(self.grid_size):
                self.grid[row][col_index] = None
            # 移除该列的所有中立棋子
            self.neutral_cells = [(x, y) for (x, y) in self.neutral_cells if x != col_index]
    
    def update_trap(self, position: Tuple[int, int], is_trapped: bool) -> None:
        """
        更新不可用格子的逻辑
        """
        x, y = position
        if is_trapped and (x, y) not in self.trapped_cells:
            self.trapped_cells.append((x, y))
            # 如果该位置原本是中立棋子，移除并清空棋盘上的标记
            if (x, y) in self.neutral_cells:
                self.neutral_cells.remove((x, y))
                self.grid[y][x] = None
        elif not is_trapped and (x, y) in self.trapped_cells:
            self.trapped_cells.remove((x, y))

    def move_piece(self, from_pos: Tuple[int, int], to_pos: Tuple[int, int]) -> bool:
        fx, fy = from_pos
        tx, ty = to_pos
        # 验证目标位置是否有效
        if (0 <= tx < self.grid_size and 0 <= ty < self.grid_size and
            self.grid[ty][tx] is None and 
            (tx, ty) not in self.trapped_cells):
            self.grid[ty][tx] = self.grid[fy][fx]
            self.grid[fy][fx] = None
            return True
        return False
    
    def swap_pieces(self, pos1: Tuple[int, int], pos2: Tuple[int, int]) -> bool:
        x1, y1 = pos1
        x2, y2 = pos2
        # 检查两个位置是否为中立棋子，禁止交换
        if (x1, y1) in self.neutral_cells or (x2, y2) in self.neutral_cells:
            return False
        # 检查两个位置是否都有棋子
        if self.grid[y1][x1] and self.grid[y2][x2]:
            self.grid[y1][x1], self.grid[y2][x2] = self.grid[y2][x2], self.grid[y1][x1]
            return True
        return False



    def can_move_neutral_to(self, pos: Tuple[int, int]) -> bool:
        x, y = pos
        return (
            0 <= x < self.grid_size and
            0 <= y < self.grid_size and
            self.grid[y][x] is None and
            (x, y) not in self.trapped_cells and
            (x, y) not in self.neutral_cells
        )
    
    def is_empty_cell(self, position: Tuple[int, int]) -> bool:
        """
        检查指定位置是否为空格子（未被占用且未被困住）
        """
        if position in self.trapped_cells:
            return False
        
        if position in self.neutral_cells:
            return False
        
        if self.grid[position[1]][position[0]] is not None:
            return False
        
        return True

    def get_empty_cells(self) -> list[Tuple[int, int]]:
        """
        获取所有可用的空格子（未被占用且未被困住）
        """
        empty_cells = []
        for y in range(self.grid_size):
            for x in range(self.grid_size):
                if self.grid[y][x] is None and (x, y) not in self.trapped_cells:
                    empty_cells.append((x, y))
        return empty_cells

    # def place_neutral_piece(self, position: Tuple[int, int]) -> bool:
    #     """
    #     在指定位置放置一个中立棋子（如 emoji）
    #     """
    #     x, y = position
    #     if (0 <= x < self.grid_size and 0 <= y < self.grid_size and
    #         self.grid[y][x] is None and (x, y) not in self.trapped_cells):
    #         self.grid[y][x] = NEUTRAL_PIECE_ICON
    #         return True
    #     return False

    def shuffle_board(self) -> None:
        """
        随机打乱所有玩家棋子的分布（不动陷阱格子和中立棋子）。
        打乱后如果已经有人获胜，则重新打乱，最多尝试10次。
        """
        from controller.util import WinChecker  # 延迟导入，避免循环依赖
        import random

        movable_positions = []
        movable_symbols = []
        for y in range(self.grid_size):
            for x in range(self.grid_size):
                if ((x, y) not in self.trapped_cells and
                    (x, y) not in self.neutral_cells and
                    self.grid[y][x] is not None):
                    movable_positions.append((x, y))
                    movable_symbols.append(self.grid[y][x])

        win_checker = WinChecker()
        max_attempts = 10
        for _ in range(max_attempts):
            random.shuffle(movable_symbols)
            # 重新分配棋子
            for idx, (x, y) in enumerate(movable_positions):
                self.grid[y][x] = movable_symbols[idx]
            # 检查是否有人获胜
            if win_checker.check_win(self):
                continue  # 已经有人获胜，重新打乱
            else:
                break  # 没有获胜，打乱成功


class Model:
    """
    游戏模型，处理游戏逻辑
    """

    grid_manager: GridManager
    player_manager: PlayerManager

    selected_skill: Optional[Skill] # 选中的技能
    selected_grid_pos: Optional[Tuple[int, int]] # 选中的格子位置

    game_over: bool # 游戏是否结束
    winner: Optional[str] # 胜者

    turn_count: int # 回合计数器

    event_message: Optional[str] # 事件消息


    def __init__(self):

        self.init()


    def init(self):
        """
        初始化模型
        """
        self.grid_manager = GridManager()
        self.player_manager = PlayerManager()

        # 重置游戏状态
        self.winner = None
        self.selected_skill = None
        self.selected_grid_pos = None
        self.game_over = False
        self.event_message = None
        self.turn_count = 0

